The attached patch fixes two problems I ran into with the swiotlb code
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 6 Sep 2005 18:25:00 +0000 (18:25 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 6 Sep 2005 18:25:00 +0000 (18:25 +0000)
in unstable (changeset aeaa3c83f6e5). Tested on a dual Opteron x86-64
machine with 4GB of memory and a tg3 modified to only DMA below 2GB.

- swiotlb_dma_supported() checked that the device DMA mask was equal
or bigger than 4GB, when in fact all that's needed is that the device
be able to DMA into the swiotlb aperture (1GB on my AMD x86-64
machine). Some device are actually only 31-bit DMA capable, so this
would've tripped them.

- On some platforms, PCI unmaps and syncs are nops, so there's no need to
keep track of the dma_addr they need after the initial mapping. The
DMA API supports this via the DECLARE_PCI_UNMAP_ADDR macros (see
Documentation/DMA-mapping.txt). Since the swiotlb code does make us of
the dma_addr for swiotlb_unmap_xxx and (more importantly)
swiotlb_dma_sync_xxx, we need to define them to something
meaningful.

Signed-Off-By: Muli Ben-Yehuda <mulix@mulix.org>
linux-2.6-xen-sparse/arch/xen/i386/kernel/swiotlb.c
linux-2.6-xen-sparse/include/asm-xen/asm-i386/pci.h
linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pci.h

index d72d9203763e0b1eb9cee392b1d965636b4d6806..7d3be682d1df8b99c5d30a316b2465221ddb6b03 100644 (file)
@@ -51,7 +51,7 @@ static unsigned long iotlb_nslabs;
  * swiotlb_sync_single_*, to see if the memory was in fact allocated by this
  * API.
  */
-static dma_addr_t iotlb_bus_start, iotlb_bus_mask;
+static dma_addr_t iotlb_bus_start, iotlb_bus_end, iotlb_bus_mask;
 
 /* Does the given dma address reside within the swiotlb aperture? */
 #define in_swiotlb_aperture(a) (!(((a) ^ iotlb_bus_start) & iotlb_bus_mask))
@@ -157,6 +157,7 @@ swiotlb_init_with_default_size (size_t default_size)
        io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
 
        iotlb_bus_start = virt_to_bus(iotlb_virt_start);
+       iotlb_bus_end   = iotlb_bus_start + bytes;
        iotlb_bus_mask  = ~(dma_addr_t)(bytes - 1);
 
        printk(KERN_INFO "Software IO TLB enabled: \n"
@@ -165,7 +166,7 @@ swiotlb_init_with_default_size (size_t default_size)
               " Kernel range: 0x%016lx - 0x%016lx\n",
               bytes >> 20,
               (unsigned long)iotlb_bus_start,
-              (unsigned long)iotlb_bus_start + bytes,
+              (unsigned long)iotlb_bus_end,
               (unsigned long)iotlb_virt_start,
               (unsigned long)iotlb_virt_start + bytes);
 }
@@ -191,6 +192,10 @@ swiotlb_init(void)
 
        if (swiotlb)
                swiotlb_init_with_default_size(64 * (1<<20));
+
+       printk(KERN_INFO "swiotlb is %sabled%s\n", 
+              (swiotlb ? "en" : "dis"), 
+              (swiotlb_force ? " (forced)" : ""));
 }
 
 static void
@@ -424,13 +429,6 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
        }
 
        dev_addr = virt_to_bus(map);
-
-       /*
-        * Ensure that the address returned is DMA'ble
-        */
-       if (address_needs_mapping(hwdev, dev_addr))
-               panic("map_single: bounce buffer is not DMA'ble");
-
        return dev_addr;
 }
 
@@ -632,7 +630,7 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr)
 int
 swiotlb_dma_supported (struct device *hwdev, u64 mask)
 {
-       return (mask >= 0xffffffffUL);
+       return (mask >= (iotlb_bus_end - 1));
 }
 
 EXPORT_SYMBOL(swiotlb_init);
index 707f4da83f142a7128d701fda856e36e297fb6e9..4e521c735d2620e96083317fa95ffeb581c79223 100644 (file)
@@ -43,9 +43,33 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
 
 struct pci_dev;
 
+#ifdef CONFIG_SWIOTLB
+
+
 /* On Xen we use SWIOTLB instead of blk-specific bounce buffers. */
 #define PCI_DMA_BUS_IS_PHYS    (0)
 
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
+       dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
+       __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)                 \
+       ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
+       (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)                   \
+       ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
+       (((PTR)->LEN_NAME) = (VAL))
+
+#else
+
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS    (1)
+
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -54,6 +78,8 @@ struct pci_dev;
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
+#endif
+
 /* This is always fine. */
 #define pci_dac_dma_supported(pci_dev, mask)   (1)
 
index 119ccdfb72a0790c4e222ee3915ce321b0570e12..9181f47e9dda513919b644f4fc8c6d3824c862cd 100644 (file)
@@ -63,6 +63,25 @@ extern int iommu_setup(char *opt);
 extern int iommu_sac_force;
 #define pci_dac_dma_supported(pci_dev, mask)   (!iommu_sac_force)
 
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
+       dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
+       __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)                 \
+       ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
+       (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)                   \
+       ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
+       (((PTR)->LEN_NAME) = (VAL))
+
+#elif defined(CONFIG_SWIOTLB)
+
+#define PCI_DMA_BUS_IS_PHYS    0
+
+#define pci_dac_dma_supported(pci_dev, mask)    1
+
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
        dma_addr_t ADDR_NAME;
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
@@ -79,9 +98,7 @@ extern int iommu_sac_force;
 #else
 /* No IOMMU */
 
-/* On Xen we use SWIOTLB instead of blk-specific bounce buffers. */
-#define PCI_DMA_BUS_IS_PHYS    (0)
-
+#define PCI_DMA_BUS_IS_PHYS    1
 #define pci_dac_dma_supported(pci_dev, mask)    1
 
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)